package com.cxx.purchasecharge.component.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cxx.purchasecharge.component.bean.ActionResult;
import com.cxx.purchasecharge.component.bean.ActionResult.ActionResultStatus;
import com.cxx.purchasecharge.component.bean.CustomerBean;
import com.cxx.purchasecharge.component.bean.DataGridRequestForm;
import com.cxx.purchasecharge.component.bean.GenericPagingResult;
import com.cxx.purchasecharge.component.bean.LoginUser;
import com.cxx.purchasecharge.component.bean.PCApplicationContext;
import com.cxx.purchasecharge.component.bean.PaymentBean;
import com.cxx.purchasecharge.component.exception.ApplicationException;
import com.cxx.purchasecharge.component.utils.AjaxUtils;
import com.cxx.purchasecharge.component.utils.BeanConvertUtils;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.component.utils.MessageProperties;
import com.cxx.purchasecharge.core.config.PurchaseChargeProperties;
import com.cxx.purchasecharge.core.model.CustomerTypeCode;
import com.cxx.purchasecharge.core.model.persistence.Customer;
import com.cxx.purchasecharge.core.model.persistence.Order;
import com.cxx.purchasecharge.core.model.persistence.Payment;
import com.cxx.purchasecharge.core.util.DateUtils;
import com.cxx.purchasecharge.dal.PaymentDao;
import com.cxx.purchasecharge.service.AuditLogService;
import com.cxx.purchasecharge.service.QueryService;

@Controller
@RequestMapping ("/provider")
public class ProviderManager
{
    private static final Logger logger = Logger.getLogger (ProviderManager.class);

    @Autowired
    private QueryService queryService;
    @Autowired
    private AuditLogService auditLogService;
    @Autowired
    private PaymentDao paymentDao;
    @Autowired
    private PCApplicationContext pcContext;

    @RequestMapping (value = "/")
    public String redirectToProviderManagement (ModelMap model)
    {
        return "providerManagement";
    }

    @RequestMapping (value = "/checkExist", method = RequestMethod.POST)
    public @ResponseBody
    String checkExist (@RequestParam String custoId, @RequestParam String name)
    {
        if (StringUtils.isBlank (custoId))
        {
            // new
            Customer obj = queryService.getCustomer (name);
            if (null != obj)
            {
                return "false";
            }
        }
        else
        {
            // edit
            long id = Long.parseLong (custoId);
            Customer customer = queryService.getCustomer (name);
            if (null != customer && customer.getId () != id)
            {
                return "false";
            }
        }

        return "true";
    }

    @RequestMapping (value = "/getAll", method = RequestMethod.POST)
    public @ResponseBody
    String getProviders (DataGridRequestForm dataGridRequestForm, HttpServletRequest request) throws Exception
    {
        logger.debug (dataGridRequestForm);
        int page = dataGridRequestForm.getPage () - 1;
        int size = dataGridRequestForm.getRows ();
        String sortField = parseSortField (dataGridRequestForm.getSort ());
        String order = dataGridRequestForm.getOrder ();
        Pageable pageable = new PageRequest (page, size, new Sort ("asc".equalsIgnoreCase (order) ? Direction.ASC
                                                                                                 : Direction.DESC,
                                                                   sortField));
        String searchKey = (null == dataGridRequestForm.getSearchKey () ? "" : dataGridRequestForm.getSearchKey ()
                                                                                                  .trim ());
        LoginUser loginUser = pcContext.getLoginUser (request);
        if (null != loginUser)
        {
            Page <Customer> customerPage = queryService.findByFuzzy (CustomerTypeCode.PROVIDER, pageable, searchKey,
                                                                     loginUser.getUserId (), loginUser.isAdmin ());
            List <Customer> customerList = customerPage.getContent ();

            long total = customerPage.getTotalElements ();
            GenericPagingResult <CustomerBean> customerPagingResult = new GenericPagingResult <CustomerBean> ();
            List <CustomerBean> customerBeans = BeanConvertUtils.customerList2CustomerBeanList (customerList);
            customerPagingResult.setRows (customerBeans);
            customerPagingResult.setTotal (total);
            
            float sumUnpay = queryService.countCustomerUnpay (CustomerTypeCode.PROVIDER, searchKey,
                                                              loginUser.getUserId (), loginUser.isAdmin ());
            List<Map<String, String>> footer = new ArrayList <Map<String,String>> ();
            Map<String, String> map = new HashMap <String, String>();
            map.put ("dealMoney", "合计: " + sumUnpay);
            footer.add (map);
            customerPagingResult.setFooter (footer);

            JSONObject jsonObject = JSONObject.fromObject (customerPagingResult);
            return jsonObject.toString ();
        }
        else
        {
            throw new ApplicationException ();
        }
    }

    private String parseSortField (final String sortField)
    {
        String sortFieldAfterParse = "shortName";
        if (!StringUtils.isBlank (sortField))
        {
            if (ComponentConstants.REG_FUND.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.REGISTER_FUND;
            }
            else if (ComponentConstants.REG_DATE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.REGISTER_DATE;
            }
        }
        return sortFieldAfterParse;
    }

    @RequestMapping (value = "/getPaymentByProvider", method = RequestMethod.POST)
    public @ResponseBody
    String getPaymentByProvider (long providerId)
    {
//        List <Payment> payments = paymentDao.findByCustomerId (providerId);
        Date end = new Date ();
        Date start = DateUtils.getDateBefore (end, PurchaseChargeProperties.getViewPaidDaysForSalesman ());
        List <Payment> payments = paymentDao.findByAdvance (providerId, start, end);
        JSONArray jsonArr = JSONArray.fromObject (BeanConvertUtils.paymentList2PaymentBeanList (payments));
        return jsonArr.toString ();
    }

    @Transactional
    @RequestMapping (value = "/newProvider", method = RequestMethod.POST)
    public @ResponseBody
    String addProvider (@Valid CustomerBean customerBean, BindingResult bindingResult, HttpServletRequest request)
    {
        if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                // check whether the contact selected is using by other provider
                updateRelativeProvider (customerBean, request);

                customerBean.setTypeCode (CustomerTypeCode.PROVIDER);
                Customer customer = BeanConvertUtils.customerBean2Customer (customerBean);
                // customer = baseCustomerDao.save (customer);
                auditLogService.addCustomer (customer, pcContext.getLoginUser (request).getUserId ());
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_SUCCESS,
                                                                                     ComponentConstants.MSG_PROVIDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_FAIL,
                                                                                     ComponentConstants.MSG_PROVIDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/updateProvider", method = RequestMethod.POST)
    public @ResponseBody
    String updateProvider (CustomerBean customerBean, BindingResult bindingResult, HttpServletRequest request)
    {
        if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                // check whether the contact selected is using by other provider
                updateRelativeProvider (customerBean, request);

                customerBean.setTypeCode (CustomerTypeCode.PROVIDER);
                // baseCustomerDao.save (BeanConvertUtils.customerBean2Customer
                // (customerBean));
                auditLogService.updateCustomer (BeanConvertUtils.customerBean2Customer (customerBean),
                                                pcContext.getLoginUser (request).getUserId ());
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_PROVIDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_FAIL,
                                                                                     ComponentConstants.MSG_PROVIDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
    }

    private void updateRelativeProvider (CustomerBean customerBean, HttpServletRequest request) throws Exception
    {
        // if (StringUtils.isNotBlank (customerBean.getId ()))
        // {
        // if (null != customerBean.getContactBean ()
        // && StringUtils.isNotBlank (customerBean.getContactBean ().getId ()))
        // {
        // long customerId = Long.parseLong (customerBean.getId ());
        // long contactId = Long.parseLong (customerBean.getContactBean ().getId
        // ());
        // Customer customer = queryService.getCustomerByContact (contactId);
        // if (null != customer && customer.getId () != customerId)
        // {
        // customer.setContact (null);
        // // baseCustomerDao.save (customer);
        // auditLogService.updateCustomer (customer, pcContext.getLoginUser
        // (request).getUserId ());
        // }
        // }
        // else if (null != customerBean.getContactBean ()
        // && StringUtils.isBlank (customerBean.getContactBean ().getId ())
        // && StringUtils.isBlank (customerBean.getContactBean ().getName ()))
        // {
        // Customer customer = queryService.getCustomer (Long.parseLong
        // (customerBean.getId ()));
        // if (null != customer)
        // {
        // customer.setContact (null);
        // // baseCustomerDao.save (customer);
        // auditLogService.updateCustomer (customer, pcContext.getLoginUser
        // (request).getUserId ());
        // }
        // }
        // }
        // else
        // {
        // if (null != customerBean.getContactBean ()
        // && StringUtils.isNotBlank (customerBean.getContactBean ().getId ()))
        // {
        // long contactId = Long.parseLong (customerBean.getContactBean ().getId
        // ());
        // Customer customer = queryService.getCustomerByContact (contactId);
        // if (null != customer)
        // {
        // customer.setContact (null);
        // // baseCustomerDao.save (customer);
        // auditLogService.updateCustomer (customer, pcContext.getLoginUser
        // (request).getUserId ());
        // }
        // }
        // }
    }

    @Transactional
    @RequestMapping (value = "/updatePaid", method = RequestMethod.POST)
    public @ResponseBody
    String updatePaid (PaymentBean paymentBean, BindingResult result, HttpServletRequest request)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                Payment payment = BeanConvertUtils.paymentBean2Payment (paymentBean);
                // paymentDao.save (payment);
                // Customer customer = baseCustomerDao.findById
                // (payment.getCustomer ().getId ());
                // baseCustomerDao.updateDealMoney (customer.getDealMoney () -
                // payment.getPaid (), customer.getId ());
                auditLogService.addPayment (payment, pcContext.getLoginUser (request).getUserId ());
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_PROVIDER_PAID))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_FAIL,
                                                                                     ComponentConstants.MSG_PROVIDER_PAID))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/delProvider", method = RequestMethod.POST)
    public @ResponseBody
    String deleteProvider (@RequestParam String ids, HttpServletRequest request)
    {
        if (null != ids && ids.trim ().length () > 0)
        {
            List <Customer> customers = new ArrayList <Customer> ();
            Customer customer;
            if (ids.indexOf (";") != -1)
            {
                String[] idArr = ids.split (";");
                for (String typeId : idArr)
                {
                    customer = new Customer ();
                    customer.setId (Long.parseLong (typeId));
                    customers.add (customer);
                }
            }
            else
            {
                customer = new Customer ();
                customer.setId (Long.parseLong (ids));
                customers.add (customer);
            }

            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                // baseCustomerDao.delete (customers);
                StringBuilder sb = new StringBuilder ();
                for (Customer model : customers)
                {
                    List <Order> orders = queryService.getOrderByCustomer (model.getId ());
                    if (CollectionUtils.isNotEmpty (orders))
                    {
                        sb.append (model.getId () + ",");
                    }
                    else
                    {
                        auditLogService.deleteCustomer (model, pcContext.getLoginUser (request).getUserId ());
                    }
                }
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_PROVIDER_PAID))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_FAIL,
                                                                                     ComponentConstants.MSG_PROVIDER_PAID))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            logger.error (ActionResultStatus.BAD_REQUEST);
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
    }
}
